#!/usr/bin/env python3
"""提供命令列介面"""
import argparse
import io
import logging
import os
import sys
from contextlib import nullcontext

from . import DEFAULT_CONFIG_FILE
from . import generate as _generate
from . import load_config
from . import syntaxparser as _syntaxparser


def _load_config_from_args(args):
    if args.config is not None:
        conf_file = args.config
        if not os.path.isfile(conf_file):
            raise RuntimeError(f'Specified config file "{conf_file}" does not exist.')
    else:
        conf_file = os.path.normpath(os.path.join(args.root, DEFAULT_CONFIG_FILE))

    return load_config(conf_file)


def generate(args):
    """把笈成資料根目錄下的原始資料輸出為靜態站台"""
    conf = _load_config_from_args(args)
    _generate.log.setLevel(args.verbosity)
    gen = _generate.StaticSiteGenerator(root=args.root, conf=conf)
    gen.run(force=args.force)


def clean(args):
    """清除笈成資料根目錄下已產生的靜態站台檔案及快取檔"""
    conf = _load_config_from_args(args)
    _generate.log.setLevel(args.verbosity)
    gen = _generate.StaticSiteGenerator(root=args.root, conf=conf)
    gen.clean()


def parse(args):
    """解析檔案或文字並輸出為指定格式的檔案或文字"""
    conf = _load_config_from_args(args)
    theme = conf.get('theme', 'default')
    assets = conf.get('assets', {})
    assets.update(conf.get('theme_assets', {}).get(theme, {}))

    parser = _syntaxparser.Parser(
        char_subst_table=assets.get('char_subst_table'),
        renderer_filter=assets.get('renderer_filter'),
    )

    with (
        open(args.ifile, 'rb')
        if args.ifile is not None
        else io.BytesIO(sys.stdin.buffer.read())
    ) as fh:
        parser.run(fh, imode=args.imode, omode=args.omode)

    with (
        open(args.ofile, 'w', encoding='UTF-8', newline='')
        if args.ofile is not None
        else nullcontext(sys.stdout)
    ) as fh:
        fh.write(parser.output)


def parse_args(argv=None):
    """解析命令列參數"""
    # Improve program name when executed through python -m
    # NOTE: We don't expect a bad command name such as having a space.
    if os.path.basename(sys.argv[0]) == '__main__.py':
        prog = f'{os.path.basename(sys.executable)} -m jicheng'
    else:
        prog = None

    parser = argparse.ArgumentParser(prog=prog,
                                     description="""笈成靜態站台產生器""")
    parser.add_argument('-r', '--root', default='',
                        help="""指定笈成資料根目錄。預設：目前目錄""")
    parser.add_argument('-c', '--config',
                        help="""指定要使用的設定檔。預設：笈成資料根目錄下的 config.yaml""")
    parser.add_argument('-q', '--quiet', dest='verbosity', const=logging.WARNING, default=logging.INFO, action='store_const',
                        help="""不輸出執行訊息""")
    parser.add_argument('-v', '--verbose', dest='verbosity', const=logging.DEBUG, default=logging.INFO, action='store_const',
                        help="""也輸出除錯訊息""")
    subparsers = parser.add_subparsers(metavar='COMMAND', required=True,
                                       help="""要執行的子命令。可加 --help (-h) 參數查閱操作說明，如：%(prog)s g -h""")

    # subcommand: generate (g)
    parser_generate = subparsers.add_parser('generate', aliases=['g'],
                                            help="""產生靜態站台""",
                                            description=generate.__doc__)
    parser_generate.set_defaults(func=generate)
    parser_generate.add_argument('-f', '--force', dest='force', default=False, action='store_true',
                                 help="""強制重新產生所有頁面，無論是否有變更""")

    # subcommand: clean
    parser_clean = subparsers.add_parser('clean',
                                         help="""清除靜態站台檔案及快取檔""",
                                         description=clean.__doc__)
    parser_clean.set_defaults(func=clean)

    # subcommand: parse (p)
    parser_parse = subparsers.add_parser('parse', aliases=['p'],
                                         help="""解析檔案及輸出""",
                                         description=parse.__doc__)
    parser_parse.set_defaults(func=parse)
    parser_parse.add_argument('-i', '--input-file', dest='ifile', nargs='?',
                              help="""輸入檔案。預設：命令列標準輸入""")
    parser_parse.add_argument('-o', '--output-file', dest='ofile', nargs='?',
                              help="""輸出檔案。預設：命令列標準輸出""")
    parser_parse.add_argument('-l', '--lexer-mode', dest='imode', nargs='?', default='html',
                              help="""輸入格式。預設：%(default)s""")
    parser_parse.add_argument('-r', '--renderer-mode', dest='omode', nargs='?', default='html',
                              help="""輸出格式。預設：%(default)s""")

    return parser.parse_args(argv)


def main():
    args = parse_args()
    args.func(args)


if __name__ == '__main__':
    main()
